package cl.solidit.geomanagement.web.controller;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.jxls.transformer.XLSTransformer;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.codehaus.jackson.map.ObjectMapper;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import cl.solidit.geomanagement.persistance.ComunaDAO;
import cl.solidit.geomanagement.persistance.PersonaDAO;
import cl.solidit.geomanagement.persistance.PropiedadDAO;
import cl.solidit.geomanagement.persistance.UserDAO;
import cl.solidit.geomanagement.persistance.VisitaDAO;
import cl.solidit.geomanagement.persistance.model.Comuna;
import cl.solidit.geomanagement.persistance.model.Persona;
import cl.solidit.geomanagement.persistance.model.Propiedad;
import cl.solidit.geomanagement.persistance.model.Usuario;
import cl.solidit.geomanagement.persistance.model.Visita;
import cl.solidit.geomanagement.persistance.util.FiltroPropiedades;
import cl.solidit.geomanagement.web.controller.comunication.JSONProperty;

/**
 * Handles requests for the application home page.
 */
@Controller
public class ControlPanelController {

	private static final Logger logger = LoggerFactory
			.getLogger(ControlPanelController.class);
	@Autowired
	private PersonaDAO personaDAO;
	@Autowired
	private PropiedadDAO propiedadDAO;
	@Autowired
	private UserDAO userDAO;
	@Autowired
	VisitaDAO visitaDAO;
	@Autowired
	ComunaDAO comunaDAO;

	/**
	 * Simply selects the home view to render by returning its name.
	 */
	@RequestMapping(value = "/control_panel", method = RequestMethod.GET)
	public ModelAndView controlPanle(
			@RequestParam(required = false) String filter) {
		HashMap<String, Object> map = new HashMap<String, Object>();
		FiltroPropiedades fp = new FiltroPropiedades();
		map.put("agentes", personaDAO.getAgentes());
		map.put("listaComunas",comunaDAO.traerComuna());
		if (filter != null) {
			try {
				byte[] json = Base64.decodeBase64(filter);
				System.out.println(new String(json, "UTF-8"));
				ObjectMapper mapper = new ObjectMapper();
				fp = mapper.readValue(json, FiltroPropiedades.class);
			} catch (Exception e) {
				logger.warn("No se pudo deserializar el filtro", e);
			}
		}
		map.put("filter", fp);

		return new ModelAndView("control_panel", map);
	}

	@Transactional
	@RequestMapping(value = "/agent_panel/${id}", method = RequestMethod.GET)
	public ModelAndView agentPanel(@PathVariable Long id) {

		Usuario usuario = userDAO.findById(id);

		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("listaComunas",comunaDAO.traerComuna());
		List<Visita> listaVisita = visitaDAO.consultarVisitaPendiente(id);
		for (Visita v : listaVisita) {
			Hibernate.initialize(v.getCliente());
			Hibernate.initialize(v.getPropiedad());
		}

		FiltroPropiedades fp = new FiltroPropiedades();
		map.put("filter", fp);
		map.put("listaVisita", listaVisita);
		map.put("usuario", usuario);

		return new ModelAndView("agent_panel", map);
	}

	@Transactional
	@RequestMapping(value = "/agent_panel", method = RequestMethod.GET)
	public ModelAndView agentPanel(HttpServletRequest request) {
		
		
		return this.agentPanel(Long.parseLong(request.getSession()
				.getAttribute("userId").toString()));

	}

	@Transactional
	@RequestMapping(value = { "/control_panel/do_filter",
			"/agent_panel/do_filter" }, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
	public @ResponseBody String doFilter(
			@ModelAttribute("filter") FiltroPropiedades filter,
			HttpServletRequest request) {
		List<Propiedad> propiedades = propiedadDAO.search(filter);
		Long countTotales=propiedadDAO.countSearchResults(filter);
		List<JSONProperty> output = new ArrayList<JSONProperty>();
		String result = "";
//		Long rol = Long.parseLong(request.getSession().getAttribute("rol")
//				.toString());
		Long rol=1L;
		if (rol != 2)
			for (Propiedad p : propiedades) {
				output.add(new JSONProperty(p));
			}
		else {
			Long userId = Long.parseLong(request.getSession()
					.getAttribute("userId").toString());

			for (Propiedad p : propiedades) {
				output.add(new JSONProperty(p, visitaDAO
						.consultarVisitaPendiente(userId, p.getId())));
			}
		}
		StringWriter writer = new StringWriter();
		try {
			Map<String,Object> fullResult=new HashMap<String, Object>();
			fullResult.put("propiedades",output);
			fullResult.put("count", countTotales);
			
			new ObjectMapper().writeValue(writer, fullResult);
			writer.flush();
			result = writer.toString();
			writer.close();
		} catch (Exception e) {
			logger.error("No se pudo serializar las propiedades", e);
		}

		return result;
	}

	@Transactional
	@RequestMapping(value = "/download", method = RequestMethod.GET)
	public ModelAndView download(@RequestParam String filter,
			HttpServletResponse response) {
		try {
			byte[] json = Base64.decodeBase64(filter);
			System.out.println(new String(json, "UTF-8"));
			ObjectMapper mapper = new ObjectMapper();
			FiltroPropiedades fp = mapper.readValue(json,
					FiltroPropiedades.class);
			List<Propiedad> propiedades = propiedadDAO.search(fp);
			List<JSONProperty> output = new ArrayList<JSONProperty>();
			for (Propiedad p : propiedades)
				output.add(new JSONProperty(p));
			HashMap<String, Object> map = new HashMap<String, Object>();
			map.put("filter", fp);
			map.put("propiedades", output);
			if (fp.getRut() != null) {
				map.put("agente", personaDAO.findByRut(fp.getRut()));
			} else {
				map.put("agente", new Persona());
			}
			SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
			if (fp.getFrom() != null) {
				map.put("from", format.format(fp.getFrom()));
			} else {
				map.put("from", "");
			}
			if (fp.getTo() != null) {
				map.put("to", format.format(fp.getTo()));
			} else {
				map.put("tp", "");
			}

			XLSTransformer transformer = new XLSTransformer();
			InputStream in = Thread.currentThread().getContextClassLoader()
					.getResourceAsStream("template.xls");
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			Workbook wb = transformer.transformXLS(in, map);
			wb.write(out);
			out.flush();
			in.close();

			String nombreFichero = "reporte.xls";

			response.setContentType("application/vnd.ms-excel");
			response.setHeader("Content-Disposition", "attachment; filename=\""
					+ nombreFichero + "\"");

			IOUtils.copy(new ByteArrayInputStream(out.toByteArray()),
					response.getOutputStream());
			out.close();
			response.flushBuffer();

		} catch (Exception e) {
			logger.warn("No se pudo descargar el pdf el filtro", e);
		}

		return null;

	}

	@Transactional
	@RequestMapping(value = "/control_panel", method = RequestMethod.POST)
	public ModelAndView listResults(
			@ModelAttribute("filter") FiltroPropiedades filter) {
		List<Propiedad> propiedades = propiedadDAO.search(filter);
		List<JSONProperty> output = new ArrayList<JSONProperty>();
		for (Propiedad p : propiedades)
			output.add(new JSONProperty(p));
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("filter", filter);
		map.put("propiedades", output);
		if (filter.getRut() != null) {
			map.put("agente", personaDAO.findByRut(filter.getRut()));
		}
		StringWriter writer = new StringWriter();
		try {
			new ObjectMapper().writeValue(writer, filter);
			writer.flush();
			String json = writer.toString();
			writer.close();
			String base64 = Base64.encodeBase64String(json.getBytes());
			map.put("urlSafeFilter", base64);
		} catch (Exception e) {
			logger.warn("No se pudo serializar el filtro", e);
		}

		return new ModelAndView("reporte", map);

	}

}
